package ssm.core.web.servlet;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.web.servlet.HttpServletBean;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * @author jinqinghua@gmail.com
 * @version 2009/06/04 rewrite it as HttpServletBean
 * @version 2010/01/27 add more code type and u can custom code strings
 * @version 2012/08/04 static final the VERIFICATION_CODE_SESSION_KEY
 */
@SuppressWarnings("restriction")
public class VerificationCodeServlet extends HttpServletBean {
	public static final String SESSION_KEY_VERIFICATION_CODE = "ssm.core.web.servlet.verificationCode";
	private static final long serialVersionUID = -6514357839698714384L;
	/**
	 * 验证码类型，目前支持以下类型：<br />
	 * <ul>
	 * <li>Number: 数字</li>
	 * <li>Alphabetic：字母</li>
	 * <li>Alphanumeric：数字和字母</li>
	 * <li>Ascii：Ascii码</li>
	 * <li>Custom：自定义验证码，请在codeString中配置验证码字符</li>
	 * </ul>
	 * 如果不为上面类型中的任意一个，默认为数字<br />
	 */
	private String codeType = "Number";

	/**
	 * 验证码数量，默认为4
	 */
	private int codeCount = 4;

	/**
	 * 自定义的验证码字符，默认为数字
	 */
	private String codeString = "0123456789";

	private int imageWidth = 60;

	private int imageHeight = 18;

	private String fontName = "Arial Black";

	/**
	 * 0:PLAIN;1:BOLD;2:ITALIC
	 */
	private int fontStyle = Font.PLAIN;

	private int fontSize = 16;

	private byte randomNumber = 127;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			java.io.IOException {

		response.setHeader("Pragma", "no-cache"); // HTTP 1.0
		response.addHeader("Cache-Control", "must-revalidate");
		response.addHeader("Cache-Control", "no-cache");
		response.addHeader("Cache-Control", "no-store");
		response.setDateHeader("Expires", 0);
		response.setContentType("image/jpeg");

		BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
		Random random = new Random();
		Graphics g = image.getGraphics();
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, imageWidth, imageHeight);

		// draw disturbing line
		// g.setColor(Color.GREEN);
		int randomInt = randomNumber & 0xff; // byte[-128->127] --> int[0->256]
		int nextRandomInt = 255 - randomInt;
		for (int i = 0; i < randomInt; i++) {
			g.setColor(new Color(randomInt + random.nextInt(nextRandomInt), randomInt + random.nextInt(nextRandomInt),
					randomInt + random.nextInt(nextRandomInt)));
			int x = random.nextInt(imageWidth);
			int y = random.nextInt(imageHeight);
			int xl = random.nextInt(12);
			int yl = random.nextInt(12);
			g.drawLine(x, y, x + xl, y + yl);
		}

		String randomCode = getVerificationCodeCode(codeCount, codeType);
		Font font = new Font(fontName, fontStyle, fontSize);
		g.setFont(font);

		for (int i = 0; i < codeCount; i++) {
			g.setColor(new Color(20 + random.nextInt(randomInt), 20 + random.nextInt(randomInt), 20 + random
					.nextInt(randomInt)));
			// g.drawString(String.valueOf(randomCode.charAt(i)), 13 * i + 6, 16);
			g.drawString(String.valueOf(randomCode.charAt(i)), (fontSize - 3) * i + 6, fontSize); // 字体间距控制
		}
		// draw border
		// g.setColor(Color.BLACK);
		// g.drawRect(0, 0, imageWidth - 1, imageHeight - 1);

		HttpSession session = request.getSession(true);
		session.setAttribute(SESSION_KEY_VERIFICATION_CODE, randomCode);

		g.dispose();

		ServletOutputStream sos = response.getOutputStream();
		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(sos);
		encoder.encode(image);
	}

	private String getVerificationCodeCode(int count, String type) {
		if ("Number".equalsIgnoreCase(type)) {
			return RandomStringUtils.randomNumeric(count);
		}
		if ("Alphabetic".equalsIgnoreCase(type)) {
			return RandomStringUtils.randomAlphabetic(count);
		}
		if ("Alphanumeric".equalsIgnoreCase(type)) {
			return RandomStringUtils.randomAlphanumeric(count);
		}
		if ("Ascii".equalsIgnoreCase(type)) {
			return RandomStringUtils.randomAscii(count);
		}
		if ("Custom".equalsIgnoreCase(type)) {
			return RandomStringUtils.random(count, codeString);
		}
		return RandomStringUtils.randomNumeric(count);
	}

	public VerificationCodeServlet() {
		super();
	}

	public String getCodeType() {
		return codeType;
	}

	public void setCodeType(String codeType) {
		this.codeType = codeType;
	}

	public int getCodeCount() {
		return codeCount;
	}

	public void setCodeCount(int codeCount) {
		this.codeCount = codeCount;
	}

	public String getCodeString() {
		return codeString;
	}

	public void setCodeString(String codeString) {
		this.codeString = codeString;
	}

	public int getImageWidth() {
		return imageWidth;
	}

	public void setImageWidth(int imageWidth) {
		this.imageWidth = imageWidth;
	}

	public int getImageHeight() {
		return imageHeight;
	}

	public void setImageHeight(int imageHeight) {
		this.imageHeight = imageHeight;
	}

	public String getFontName() {
		return fontName;
	}

	public void setFontName(String fontName) {
		this.fontName = fontName;
	}

	public int getFontStyle() {
		return fontStyle;
	}

	public void setFontStyle(int fontStyle) {
		this.fontStyle = fontStyle;
	}

	public int getFontSize() {
		return fontSize;
	}

	public void setFontSize(int fontSize) {
		this.fontSize = fontSize;
	}

	public byte getRandomNumber() {
		return randomNumber;
	}

	public void setRandomNumber(byte randomNumber) {
		this.randomNumber = randomNumber;
	}
}